package com.ferry.transport.api.config;
import	java.util.ArrayList;

import java.util.List;

/**
 * Created by daiyong
 */
public class ParentConfig implements TcpConfig {

	private volatile int ioRatio = 99;
	private volatile int backlog = 1024;
	private volatile int rcvBuf = -1;
	private volatile boolean reuseAddress = true;
	private volatile int pendingFastOpenRequestsThreshold = -1;
	private volatile int tcpDeferAccept = -1;
	private volatile boolean edgeTriggered = true;
	private volatile boolean reusePort = false;
	private volatile boolean ipFreeBind = false;
	private volatile boolean ipTransparent = false;

	@Override
	public List<TcpOption<?>> getOptions() {
		List<TcpOption<?>> options = new ArrayList<> ();
		options.add(TcpOption.IO_RATIO);
		options.add(TcpOption.SO_BACKLOG);
		options.add(TcpOption.SO_REUSEADDR);
		options.add(TcpOption.TCP_FASTOPEN);
		options.add(TcpOption.TCP_DEFER_ACCEPT);
		options.add(TcpOption.EDGE_TRIGGERED);
		options.add(TcpOption.SO_REUSEPORT);
		options.add(TcpOption.IP_FREEBIND);
		options.add(TcpOption.IP_TRANSPARENT);
		return options;
	}

	@Override
	public <T> T getOption(TcpOption<?> option) {

		if (option == TcpOption.IO_RATIO) {
			return (T) Integer.valueOf(getIoRatio());
		}
		if (option == TcpOption.SO_BACKLOG) {
			return (T) Integer.valueOf(getBacklog());
		}
		if (option == TcpOption.SO_RCVBUF) {
			return (T) Integer.valueOf(getRcvBuf());
		}
		if (option == TcpOption.SO_REUSEADDR) {
			return (T) Boolean.valueOf(isReuseAddress());
		}
		if (option == TcpOption.TCP_FASTOPEN) {
			return (T) Integer.valueOf(getPendingFastOpenRequestsThreshold());
		}
		if (option == TcpOption.TCP_DEFER_ACCEPT) {
			return (T) Integer.valueOf(getTcpDeferAccept());
		}
		if (option == TcpOption.EDGE_TRIGGERED) {
			return (T) Boolean.valueOf(isEdgeTriggered());
		}
		if (option == TcpOption.SO_REUSEPORT) {
			return (T) Boolean.valueOf(isReusePort());
		}
		if (option == TcpOption.IP_FREEBIND) {
			return (T) Boolean.valueOf(isIpFreeBind());
		}
		if (option == TcpOption.IP_TRANSPARENT) {
			return (T) Boolean.valueOf(isIpTransparent());
		}

		return null;
	}

	@Override
	public <T> boolean setOption(TcpOption<?> option, T value) {
		if (option == TcpOption.IO_RATIO) {
			setIoRatio(castToInteger(value));
		} else if (option == TcpOption.SO_BACKLOG) {
			setBacklog(castToInteger(value));
		} else if (option == TcpOption.SO_RCVBUF) {
			setRcvBuf(castToInteger(value));
		} else if (option == TcpOption.SO_REUSEADDR) {
			setReuseAddress(castToBoolean(value));
		} else if (option == TcpOption.TCP_FASTOPEN) {
			setPendingFastOpenRequestsThreshold(castToInteger(value));
		} else if (option == TcpOption.TCP_DEFER_ACCEPT) {
			setTcpDeferAccept(castToInteger(value));
		} else if (option == TcpOption.EDGE_TRIGGERED) {
			setEdgeTriggered(castToBoolean(value));
		} else if (option == TcpOption.SO_REUSEPORT) {
			setReusePort(castToBoolean(value));
		} else if (option == TcpOption.IP_FREEBIND) {
			setIpFreeBind(castToBoolean(value));
		} else if (option == TcpOption.IP_TRANSPARENT) {
			setIpTransparent(castToBoolean(value));
		}

		return true;
	}

	public int getBacklog() {
		return backlog;
	}

	public int getRcvBuf() {
		return rcvBuf;
	}

	public boolean isReuseAddress() {
		return reuseAddress;
	}

	public int getPendingFastOpenRequestsThreshold() {
		return pendingFastOpenRequestsThreshold;
	}

	public int getTcpDeferAccept() {
		return tcpDeferAccept;
	}

	public boolean isEdgeTriggered() {
		return edgeTriggered;
	}

	public boolean isReusePort() {
		return reusePort;
	}

	public boolean isIpFreeBind() {
		return ipFreeBind;
	}

	public boolean isIpTransparent() {
		return ipTransparent;
	}

	public void setBacklog(int backlog) {
		this.backlog = backlog;
	}

	public void setRcvBuf(int rcvBuf) {
		this.rcvBuf = rcvBuf;
	}

	public void setReuseAddress(boolean reuseAddress) {
		this.reuseAddress = reuseAddress;
	}

	public void setPendingFastOpenRequestsThreshold(int pendingFastOpenRequestsThreshold) {
		this.pendingFastOpenRequestsThreshold = pendingFastOpenRequestsThreshold;
	}

	public void setTcpDeferAccept(int tcpDeferAccept) {
		this.tcpDeferAccept = tcpDeferAccept;
	}

	public void setEdgeTriggered(boolean edgeTriggered) {
		this.edgeTriggered = edgeTriggered;
	}

	public void setReusePort(boolean reusePort) {
		this.reusePort = reusePort;
	}

	public void setIpFreeBind(boolean ipFreeBind) {
		this.ipFreeBind = ipFreeBind;
	}

	public void setIpTransparent(boolean ipTransparent) {
		this.ipTransparent = ipTransparent;
	}

	public int getIoRatio() {
		return ioRatio;
	}

	public void setIoRatio(int ioRatio) {
		if (ioRatio < 0) {
			ioRatio = 0;
		}
		if (ioRatio > 100) {
			ioRatio = 100;
		}
		this.ioRatio = ioRatio;
	}
	private static Integer castToInteger(Object value) {
		if (value instanceof Integer) {
			return (Integer) value;
		}

		if (value instanceof String) {
			return Integer.valueOf((String) value);
		}

		throw new IllegalArgumentException(value.getClass().toString());
	}

	private static Long castToLong(Object value) {
		if (value instanceof Long) {
			return (Long) value;
		}

		if (value instanceof String) {
			return Long.valueOf((String) value);
		}

		throw new IllegalArgumentException(value.getClass().toString());
	}

	private static Boolean castToBoolean(Object value) {
		if (value instanceof Boolean) {
			return (Boolean) value;
		}

		if (value instanceof String) {
			return Boolean.valueOf((String) value);
		}

		throw new IllegalArgumentException(value.getClass().toString());
	}
}
